package com.wuliang.interview.results;

import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 新出生的细菌20分钟可进行下一代繁育，每三十分钟繁殖两个，但是每个细菌最多可繁殖3次，细菌150分钟后死亡，请用面向对象思想实现计算n分钟内细菌总数
 * 斐波那契数列, 从1开始
 */
public class First {

    private static final Integer TIME_INTERVAL = 10;

    /**
     * 细菌对象
     */
    static class Bacterial {
        /**
         * 年龄，没三十分钟递增1
         */
        private int age = 0;

        /**
         * 繁育次数，每三十分钟递增1
         */
        private int numberOfReproduction = 0;

        /**
         * 死亡标记。用于从列表中剔除已死亡的细菌
         */
        private boolean diedFlag = false;

        /**
         * 该属性于程序无用，为了方便调试
         */
        private String name;

        /**
         * 繁育出来的孩子们
         */
        private List<Bacterial> childrenList = new ArrayList<>(6);

        public Bacterial() {
        }

        public Bacterial(String name) {
            this.name = name;
        }

        /**
         * 繁育
         */
        public void reproductionChild() {
            // 年龄递增1
            this.age++;
            // 间隔二十分钟后, 如果繁育次数小于三，则繁育两个孩子
            if (this.age > 2 && this.numberOfReproduction < 3) {
                if ((this.age - 2) % 3 == 0) {
                    int i = childrenList.size();
                    // 产两子
                    childrenList.add(new Bacterial(this.name + "-" + (++i)));
                    childrenList.add(new Bacterial(this.name + "-" + (++i)));
                    // 繁育次数递增
                    this.numberOfReproduction++;
                }
            }
            // 如果年龄等于十五，则对当前细菌的死亡标记修改为已死亡。
            if (this.age == 15) {
                this.diedFlag = true;
            }
        }

        @Override
        public String toString() {
            return "{" +
                    "name:'" + name + '\'' +
                    '}';
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) {
                return true;
            }
            if (o == null || getClass() != o.getClass()) {
                return false;
            }
            Bacterial bacterial = (Bacterial) o;
            return age == bacterial.age &&
                   numberOfReproduction == bacterial.numberOfReproduction &&
                   diedFlag == bacterial.diedFlag &&
                   Objects.equals(name, bacterial.name) &&
                   Objects.equals(childrenList, bacterial.childrenList);
        }

        @Override
        public int hashCode() {
            return Objects.hash(age, numberOfReproduction, diedFlag, name, childrenList);
        }
    }

    /**
     * 根据给定时长，计算给定时间内细菌生长的数量
     *
     * @param minute 输入分钟时长
     * @return 时长结束后，细菌的总数
     */
    public static Integer amountBacterial(int minute) {
        // 声明一个根节点
        Bacterial root = new Bacterial("root");
        // 如果输入的数字少于30分钟，则返回1
        if (minute < 30) {
            return 1;
        }
        // 声明一个细菌集合，用来存放全部细菌
        List<Bacterial> bacterialList = new LinkedList<>();
        // 首先将根节点存放到集合中
        bacterialList.add(root);
        // 每十分钟一次遍历
        for (int i = 0; i < minute / TIME_INTERVAL; i++) {
            // 开始繁育
            reproduction(root, bacterialList);
            System.out.println("第" + i + "0分钟:" + bacterialList.size());
        }
        // 过滤掉已经死亡的细菌
        bacterialList = bacterialList.stream().filter(bacterial -> !bacterial.diedFlag).collect(Collectors.toList());
        return bacterialList.size();
    }

    /**
     * 开始繁育
     *
     * @param rootBacterial 当前结点
     */
    public static void reproduction(Bacterial rootBacterial, List<Bacterial> bacterialList) {
        // 首先是当前节点繁育
        rootBacterial.reproductionChild();
        // 如果当前节点已经繁育出来孩子了，则在让孩子进行繁育
        for (Bacterial children : rootBacterial.childrenList) {
            reproduction(children, bacterialList);
        }
        // 将子存放到细菌集合中
        bacterialList.addAll(rootBacterial.childrenList);
    }

    public static void main(String[] args) {
        System.out.println("共有细菌：" + amountBacterial(100));
    }
}
